package org.testfire.realm.model.entities;

import javax.persistence.*;
import static javax.persistence.CascadeType.ALL;
import java.io.Serializable;
import java.util.Date;
import java.util.Set;

/**
 * An Entity which represents a User record in the tbl_users table.
 */
@Entity
@Table(catalog = "lgsrealm", name = "tbl_users")
public class User implements Serializable {


	Integer id;
	String name;
	String md5;
	String pwd_hint;
	String email;

	Date created;
	Date accessed;

	Integer enabled;
	Integer verified;

	String confirm_code;

	Contact_info contact_info;

	Set User_groups;

	/**
	 * The Default Constructor.
	 * Note that a few values are set upon creation; the created date and accessed date are
	 * both set to the current date and time. If this is not a new user object, the
	 * datea will be over-written when the persisted User is read from the database, but
	 * not if we create our own user.
	 * <p/>
	 * What we are doing is setting the values for the 'default new user state'.
	 */
	public User() {
		this.enabled = 1;
		this.created = new Date(System.currentTimeMillis());
		this.accessed = new Date(System.currentTimeMillis());
		this.verified = 0; // false;

	}


	/**
	 * Get the ID of this user record.
	 * Rather than index the username, even though it is unique, we index on a
	 * generated value, which is an integer.
	 * There are better stratagies for indexing users, however this is about as simple as it
	 * can get. And the database size won't really be an issue for us, so adding the extra integer value
	 * in the table isn't going to be a problem.
	 * <p/>
	 * Using the @Id annotation we demarc the id parameter as the primary key for the tbl_users table.
	 * Additionally, we use the @GeneratedValue annotation to inform the persistence manager that this
	 * id value is generated automatically by the database/persistence-provider, and is a sequence.
	 * <p/>
	 * There is plenty more behind the @GeneratedValue annotation; see the persistence specification for
	 * more details.
	 *
	 * @return The ID for this User Entity.
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE)
	public Integer getId() {
		return this.id;
	}

	/**
	 * Set the ID value for this User. Don't do this. The persistence manager may or may not use this
	 * method, but you certainly should not.
	 *
	 * @param id The ID (which is actually an auto-generated value) for this user.
	 */
	public void setId(Integer id) {
		this.id = id;
	}

	/**
	 * Get all of the user_groups records that this user owns.
	 * The user_groups table is a mapping of users to the groups they are members of.
	 * Because on user can be a member of many groups, and one record in the user_groups table maps
	 * one userID to one GroupID, we indicate to the persistence manager that this
	 * Set of values is to be created by mapping the ID of this user to those records in the
	 * user_groups table with a user_id value that matches.
	 * <p/>
	 * One user -> multiple groups == OneToMany.
	 * The mappedBy parameter indicates the name of the field in the other table which there is a Join on.
	 *
	 * @return A Set of User_groups Entities, each representing records in the User_groups table. Each record
	 *         then indicates a Group which this user is a member of.
	 */
	@OneToMany(cascade = ALL, mappedBy = "user_id")
	public Set<User_groups> getUser_groups() {
		return User_groups;
	}

	/**
	 * Set the user group mappings on this user.
	 *
	 * @param groups A Set containing User_groups entities.
	 */
	public void setUser_groups(Set<User_groups> groups) {
		this.User_groups = groups;
	}

	/**
	 * Get the MD5 for this user. This is the password equivilent that we use for authentication.
	 *
	 * @return The User's MD5
	 */
	public String getMd5() {
		return this.md5;
	}

	/**
	 * Set the MD5 for this user.  An MD5 Checksum created from the HMAC of the user's password as a key and
	 * the concatonation of the user's username and the system salt as the data block:
	 * LGSChecksum.getHMAC_MD5(password, userName + UtilityBean.SYSTEM_SALT);
	 *
	 * @param md5 An MD5 Checksum created from the HMAC of the user's password as a key and
	 *            the concatonation of the user's username and the system salt as the data block.
	 */
	public void setMd5(String md5) {
		this.md5 = md5;
	}

	/**
	 * Get the password hint that the user has chosen.
	 *
	 * @return the password hint that the user has chosen.
	 */
	public String getPwd_hint() {
		return this.pwd_hint;
	}

	/**
	 * Set the password hint that the user has chosen.
	 *
	 * @param pwd_hint the password hint that the user has chosen.
	 */
	public void setPwd_hint(String pwd_hint) {
		this.pwd_hint = pwd_hint;
	}


	/**
	 * Get the user's email address.
	 *
	 * @return the user's email address.
	 */
	public String getEmail() {
		return this.email;
	}

	/**
	 * Set the user's email address.
	 *
	 * @param email the user's email address.
	 */
	public void setEmail(String email) {
		this.email = email;
	}


	/**
	 * Get the verified status flag indicating if the user has verified their account or not. C style boolean value
	 * (0 is false, anything else can be considered true).
	 *
	 * @return the verified status flag.
	 */
	public Integer getVerified() {
		return this.verified;
	}

	/**
	 * Set the verified status flag indicating if the user has verified their account or not.
	 * C style boolean value (0 is false, anything else can be considered true).
	 *
	 * @param verified If the user has verified their account or not.
	 */
	public void setVerified(Integer verified) {
		this.verified = verified;
	}

	/**
	 * Get the Contact_info Entity which contains the contact information for this user.
	 * While  not used in the Template, this Entity was left in to demonstrate more
	 * complex mapping operations.
	 * The OneToOne annotation indicates to the persistence manager that for every user, there
	 * exists exactly one corresponding record in the contact_info table. The JoinColumn
	 * indicates that this table (users) contains a field called 'contact_info_id' which
	 * contains the the primary key value of a contact_info record.
	 * <p/>
	 * The persistence manager will recognize that the integer value in the field 'contact_info_id'
	 * for this user represents a 'link' to the actual record in the contact_info table. It will
	 * use this information to query for the record, create the Contact_info Entity, and store it
	 * in this User Entity, for our later use.
	 *
	 * @return A Contact_info Entity.
	 */
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "contact_info_id")
	public Contact_info getContact_info() {
		return this.contact_info;
	}

	/**
	 * Set the Contact_info Entity for this User.
	 *
	 * @param contact_info A Contact_info entity.
	 */
	public void setContact_info(Contact_info contact_info) {
		this.contact_info = contact_info;
	}

	/**
	 * Get the date upon which this user's account was last accessed. This value is set by
	 * our Authentication Realm whenever the user logs in successfully.
	 * The @Temporal annotation informs the persistence context that this value
	 * is stored in the database as some form of time (temporal) data. The argument
	 * indicates exactly which sub-type.
	 *
	 * @return The date which this user last logged in to their account.
	 */
	@Temporal(TemporalType.TIMESTAMP)
	public Date getAccessed() {
		return accessed;
	}

	/**
	 * Set the last accessed date. This is handled by the LGS Authentication Realm (LGSRealm), and shouldnt'
	 * really be called manually.
	 *
	 * @param accessed The date upon which the user last accessed this account.
	 */
	public void setAccessed(Date accessed) {
		this.accessed = accessed;
	}


	/**
	 * Get the date upon which this user's account was created. This value should only be set once: in the constructor
	 * when the User Entity is created by the RegisterUserBean.
	 *
	 * @return The date this User's account was created.
	 */
	@Temporal(TemporalType.TIMESTAMP)
	public Date getCreated() {
		return created;
	}

	/**
	 * Set the date upon which this user's account was created. This value should only be set once: in the constructor
	 * when the User Entity is created by the RegisterUserBean.
	 *
	 * @param created The date this user account was created.
	 */
	public void setCreated(Date created) {
		this.created = created;
	}

	/**
	 * Get the enabled status flag indicating if this user account is enabled. C style boolean value
	 * (0 is false, anything else can be considered true).
	 *
	 * @return Zero (representing false) if this account is disabled, any other value if not.
	 */
	public Integer getEnabled() {
		return enabled;
	}

	/**
	 * Set the enabled status flag indicating if this user account is enabled. C style boolean value
	 * (0 is false, anything else can be considered true).
	 *
	 * @param enabled Zero (representing false) if this account is disabled, any other value if not.
	 */
	public void setEnabled(Integer enabled) {
		this.enabled = enabled;
	}

	/**
	 * Get the user name for this account. A value unique to our database.
	 *
	 * @return The user name for this User Entity.
	 */
	public String getName() {
		return name;
	}


	/**
	 * Get the user name for this account. A value unique to our database.
	 *
	 * @param name The user name for this User Entity.
	 */
	public void setName(String name) {
		this.name = name;
	}


	/**
	 * Get the confirmation code created for the sole purpose of allowing the user to verify their account
	 * after registration.
	 *
	 * @return The confirmation code which was set upon this user during the registration process.
	 */
	public String getConfirm_code() {
		return confirm_code;
	}

	/**
	 * Set the confirmation code created for the sole purpose of allowing the user to verify their account
	 * after registration.
	 *
	 * @param confirm_code A random value which should be sent out as part a link to the user in a confirmation e-mail.
	 */
	public void setConfirm_code(String confirm_code) {
		this.confirm_code = confirm_code;
	}
}
